﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Timers;

namespace PlanetViewer
{
    [Flags]
    public enum DebugTextPosition
    {
        UpperLeft,
        UpperRight,
        LowerLeft,
        LowerRight,
        Left,
        Right,
        Top,
        Bottom,
        Center
    }
    class DebugMessage
    {
        public string Text;
        private DebugTextPosition _position;
        private Vector2 _positionOffset;
        private SpriteFont _font;
        private float _size;
        private Color _color;

        private Vector2[] _debugTextPositions;
        /// <summary>
        /// Creates a new debug message at the specified position.
        /// </summary>
        /// <param name="position">Position of message onscreen.</param>
        /// <param name="game">The current game.</param>
        public DebugMessage(Game game, DebugTextPosition position)
        {
            _debugTextPositions = Initialize(game);

            _position = position;
            _size = 1f;
            _color = Color.Black;
        }

        /// <summary>
        /// Creates a customized debug message at the specified position with offset.
        /// </summary>
        /// <param name="position">Position of message onscreen.</param>
        /// <param name="positionOffset">Offset of display from position.</param>
        /// <param name="size">Font size.</param>
        /// <param name="color">Font Color.</param>
        /// <param name="game">The current game.</param>
        public DebugMessage(Game game,DebugTextPosition position, Vector2 positionOffset, float size, Color color)
        {
            _debugTextPositions = Initialize(game);

            this._position = position;
            this._positionOffset = positionOffset;
            this._size = size;
            this._color = color;

        }
        private Vector2[] Initialize(Game game)
        {

            this._font = game.Content.Load<SpriteFont>("debugfont");
            this.Text = String.Empty;

            DebugTextPosition[] RightAlignedFlags = { DebugTextPosition.UpperRight, DebugTextPosition.LowerRight, DebugTextPosition.Right};

            int screenWidth = game.GraphicsDevice.Viewport.Width;
            int screenHeight = game.GraphicsDevice.Viewport.Height;
            int padding = 45;
            return new Vector2[]{
            new Vector2(padding,padding), //UpperLeft
            new Vector2(screenWidth - padding,padding), //UpperRight
            new Vector2(padding,screenHeight - padding * 2 ), //LowerLeft
            new Vector2(screenWidth - padding, screenHeight - padding * 2), //LowerRight
            new Vector2(padding,screenHeight / 2), //Left
            new Vector2(screenWidth - padding,screenHeight / 2), //Right
            new Vector2(screenWidth / 2,padding), //Top
            new Vector2(screenWidth / 2,screenHeight - padding * 2), //Bottom
            new Vector2(screenWidth / 2,screenHeight/2), //Center
            };
        }

        /// <summary>
        /// Renders the text of the debug message during the draw() call.  Must be contained within a SpriteBatch.Draw() and SpriteBatch.End().
        /// </summary>
        /// <param name="spriteBatch">The spritebatch used for text rendering</param>
        public void RenderText(SpriteBatch spriteBatch)
        {
            Vector2 newPositionOffset = _positionOffset;
            int indexPosition = (int)_position;
            if (indexPosition == 1 | indexPosition == 3 | indexPosition == 5)
            {
                newPositionOffset.X -= _font.MeasureString(Text).X;
            }
            else if (indexPosition > 5)
            {
                newPositionOffset.X -= _font.MeasureString(Text).X / 2;
            }
            spriteBatch.DrawString(_font, Text, _debugTextPositions[(int)_position] + newPositionOffset, _color, 0f, Vector2.Zero, _size, SpriteEffects.None, 1f);
        }
        /// <summary>
        /// Updates the debug message text.
        /// </summary>
        /// <param name="message">New message text.</param>
        public void UpdateText(string message)
        {
            int maxCharCount = 80;
            if (message.Length > maxCharCount)
            { message = message.Substring(0, maxCharCount); }
            Text = message;
        }

    }
    class TimedDebugMessage : DebugMessage
    {
        private Timer timer;
        private int _initialTime;
        public bool Expired;

        public TimedDebugMessage(Game game, DebugTextPosition position)
            : base(game, position)
        {
            int defaultKeepAlive = 2000;
            _initializeTimer(defaultKeepAlive);
        }
        public TimedDebugMessage(Game game, DebugTextPosition position, Vector2 positionOffset, float size, Color color, int millisecondsToLive)
            : base(game, position, positionOffset, size, color)
        {
            _initializeTimer(millisecondsToLive);
        }
        private void _initializeTimer(int time)
        {
            timer = new Timer();
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Interval = time;
            timer.Enabled = true;
            timer.Start();

            _initialTime = time;
            Expired = false;
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            timer.Stop();
            timer.Enabled = false;
            Expired = true;
        }

        public void RefreshTimer()
        {
            timer.Stop();
            timer.Interval = _initialTime;
            timer.Start();
        }
    }

    /// <summary>
    /// Displays arbitrary debug text messages to the active screen.  (Note: this is not a lightweight process.)
    /// </summary>
    public class DebugMessageGroup
    {
        private Dictionary<string, TimedDebugMessage> DebugMessages;
        private List<string> ExpiredMessageID;
        private Game _game;
        private Timer internalSynchronizer;

        public DebugMessageGroup(Game game)
        {
            //Create message stores
            DebugMessages = new Dictionary<string,TimedDebugMessage> { };
            ExpiredMessageID = new List<string> { };

            //Reference active game
            this._game = game;

            //Create timer and event
            internalSynchronizer = new Timer();
            internalSynchronizer.Elapsed += new ElapsedEventHandler(internalSynchronizer_Elapsed);
            internalSynchronizer.Interval = 1000;
            internalSynchronizer.Enabled = true;
            internalSynchronizer.Start();

        }

        void internalSynchronizer_Elapsed(object sender, ElapsedEventArgs e)
        {
            PurgeExpiredMessages();
        }

        private TimedDebugMessage createNewMessage(string message,DebugTextPosition position)
        {
            TimedDebugMessage listedMessage = new TimedDebugMessage(_game, position);
            listedMessage.Text = message;
            return listedMessage;
        }
        private TimedDebugMessage createNewAdvancedMessage(string message, DebugTextPosition position, Vector2 offset, float size, Color color, int lifeTime)
        {
            TimedDebugMessage listedAdvMessage = new TimedDebugMessage(_game, position, offset, size, color, lifeTime);
            listedAdvMessage.UpdateText(message);
            return listedAdvMessage;

        }
        public void Message(string message)
        {
            Message("default", message);
        }
        public void Message(string messageName, string message)
        {
            Message(messageName, message, DebugTextPosition.UpperLeft);
        }
        public void Message(string messageName, string message, DebugTextPosition position)
        {
            if (DebugMessages.ContainsKey(messageName))
            {
                DebugMessages[messageName].UpdateText(message);
                DebugMessages[messageName].RefreshTimer();
            }
            else
            {
                DebugMessages.Add(messageName, createNewMessage(message, position));
            }
        }
        public void Message(string messageName, string message, DebugTextPosition position,Vector2 offset,float size,Color color,int lifeTime)
        {
            if (DebugMessages.ContainsKey(messageName))
            {
                DebugMessages[messageName].UpdateText(message);
                DebugMessages[messageName].RefreshTimer();
            }
            else
            {
                DebugMessages.Add(messageName, createNewAdvancedMessage(message, position, offset, size, color, lifeTime));
            }
        }
        public void RenderGroup(SpriteBatch spriteBatch)
        {
            foreach (string messageID in DebugMessages.Keys)
            {
                DebugMessages[messageID].RenderText(spriteBatch);
                if (DebugMessages[messageID].Expired)
                {
                    ExpiredMessageID.Add(messageID);
                }
            }
        }
        private void PurgeExpiredMessages()
        {
            if (ExpiredMessageID.Count > 0)
            {
                foreach (string messageID in ExpiredMessageID)
                {
                    DebugMessages.Remove(messageID);
                }
                ExpiredMessageID.Clear();
            }
        }
    }
}
